// tcp服务器
#include "stm32_server.h"

static struct shm_param para1;
struct sockaddr_in sock_t, sock_c; // 指定网络信息
static int *total;                 // 指向共享内存中数据节点总个数
static stm_node_p node_arr;        // 指向共享内存中节点缓存数组头
key_p key_val[10];                 // 初始化结构体
msgbuf_t recv_buf;                 // 接收消息缓冲区
sem_t sem;

int assignment() // 解析JSON文件，实例化到结构体中
{
    char json[2048] = "";
    FILE *fp = fopen(_PATH, "r"); // 创建文件指针
    if (fp == NULL)
    {
        perror("err: fopen");
        return -1;
    }

    int n = fread(json, 1, sizeof(json), fp); // 读取文件内容
    if (n < 0)
    {
        perror("err: fread");
        fclose(fp);
        return -1;
    }

    cJSON *root = cJSON_Parse(json); // 解析JSON数据
    if (root == NULL)
    {
        printf("Failed to parse JSON-------1.\n");
        fclose(fp);
        return -1;
    }

    cJSON *stm32 = cJSON_GetObjectItem(root, "stm32");
    if (stm32 == NULL)
    {
        printf("Failed to get stm32 object---------1.\n");
        cJSON_Delete(root);
        return -1;
    }

    cJSON *data = cJSON_GetObjectItem(stm32, "data"); // 获取数据对象
    if (data == NULL)
    {
        printf("Failed to get data object---------1.\n");
        cJSON_Delete(root);
        return -1;
    }
    int size = cJSON_GetArraySize(data); // 获取数据数组大小

    for (int i = 0; i < size; i++)
    {
        key_val[i] = (key_p)malloc(sizeof(key_p)); // 假设key_p是struct key_struct *
        if (key_val[i] == NULL)
        {
            perror("malloc");
            cJSON_Delete(root);
            fclose(fp);
            return -1;
        }
        strcpy(key_val[i]->name, cJSON_GetObjectItem(cJSON_GetArrayItem(data, i), "name")->valuestring);
        key_val[i]->key = cJSON_GetObjectItem(cJSON_GetArrayItem(data, i), "key")->valueint;
        key_val[i]->type = cJSON_GetObjectItem(cJSON_GetArrayItem(data, i), "type")->valueint;
    }

    cJSON_Delete(root); // 正确释放整个JSON树
    fclose(fp);         // 关闭文件指针
    return 0;
}

int shm_put(char buf[]) // 写入共享内存数据
{
    cJSON *root = cJSON_Parse(buf);
    if (root == NULL)
    {
        printf("Failed to parse JSON---------1.\n");
        return -1;
    }
    cJSON *stm32 = cJSON_GetObjectItem(root, "stm32");
    if (stm32 == NULL)
    {
        printf("Failed to get stm32 object---------1.\n");
        cJSON_Delete(root);
        return -1;
    }
    cJSON *data = cJSON_GetObjectItem(stm32, "data"); // 获取数据对象
    if (data == NULL)
    {
        printf("Failed to get data object---------1.\n");
        cJSON_Delete(root);
        return -1;
    }
    int size = cJSON_GetArraySize(data); // 获取数据数组大小
    printf("size: %d\n", size);

    if (assignment() < 0)
    {
        printf("err assignment\n");
        return -1;
    }

    int ret = -1;
    ret = shm_init(&para1, "shm_stm32", MAX_NODE_SIZE); // 初始化共享内存
    if (ret < 0)
    {
        return -1;
    }
    void *node_p = shm_getaddr(&para1); // 获取共享内存地址
    if (node_p == NULL)
    {
        return -1;
    }
    memset(node_p, 0, MAX_NODE_SIZE); // 清空共享内存
    total = (int *)node_p;
    node_arr = (stm_node_p)(node_p + sizeof(int));
    *total = size;

    for (int i = 0; i < size; i++)
    {
        cJSON *temp = cJSON_GetArrayItem(data, i);
        cJSON *name = cJSON_GetObjectItem(temp, "name");
        node_arr[i].type = key_val[i]->type;

        if (!strcmp(name->valuestring, key_val[i]->name))
        {
            printf("name: %s, key: %d\n", name->valuestring, key_val[i]->key);
            node_arr[i].key = key_val[i]->key;
        }
        else
            printf("err: Wrong name");

        if (node_arr[i].type == 1)
            node_arr[i].new_val.i_val = cJSON_GetObjectItem(temp, "value")->valueint;
        else if (node_arr[i].type == 2)
            node_arr[i].new_val.b_val = cJSON_GetObjectItem(temp, "value")->valueint;
        else if (node_arr[i].type == 3)
            node_arr[i].new_val.f_val = cJSON_GetObjectItem(temp, "value")->valuedouble;
        else
            printf("type err\n");
        node_arr[i].old_val = node_arr[i].new_val;
    }
    cJSON_Delete(root); // 正确释放整个JSON树
    for (int i = 0; i < size; i++)
    {
        free(key_val[i]);
    }
    return 0;
}

void *handler(void *arg) // 处理客户端请求的线程
{
    int ac_fd = *(int *)arg;
    printf("ip: %s\nport: %d\n", inet_ntoa(sock_c.sin_addr), ntohs(sock_t.sin_port));
    char buf[1024] = "";
    while (1)
    {
        sem_wait(&sem);                               // 等待信号量
        ssize_t r = recv(ac_fd, buf, sizeof(buf), 0); // 接收信息
        if (r < 0)
        {
            perror("err: recv");
            return NULL;
        }
        else if (r == 0)
        {
            printf("client exit\n");
            close(ac_fd);
            break;
        }
        else if (r > 0)
        {
            printf("%s\n", buf); // 打印接收到的信息
            shm_put(buf);
            memset(buf, 0, sizeof(buf));
        }
        sem_post(&sem); // 释放信号量
    }
}

int main(int argc, char const *argv[])
{
    int ac_fd;
    sem_init(&sem, 0, 1);
    int fd = socket(AF_INET, SOCK_STREAM, 0); // 创建
    if (fd < 0)
    {
        perror("err: socket");
        return -1;
    }

    sock_t.sin_family = AF_INET;
    sock_t.sin_port = htons(_PORT);
    sock_t.sin_addr.s_addr = INADDR_ANY;

    if (bind(fd, (struct sockaddr *)&sock_t, sizeof(sock_t)) < 0) // 绑定
    {
        perror("err: bind");
        return -1;
    }

    if (listen(fd, 6) < 0) // 监听
    {
        perror("err: listen");
        return -1;
    }
    int len = sizeof(sock_c);

    // 在TCP服务器中,有两类文件描述符
    // 一类用于通信的文件描述符:可能有多个(accept函数返回值)
    // 一类用于连接的文件描述符:只有一个(socket函数返回值)
    if ((ac_fd = accept(fd, (struct sockaddr *)&sock_c, &len)) < 0) // 接受
    {
        perror("err: accept");
        return -1;
    }
    pthread_t tid;
    if (pthread_create(&tid, NULL, handler, &ac_fd) != 0)
    {
        perror("err: pthread_create");
        return -1;
    }

    // 清空接收缓冲区
    memset(&recv_buf, 0, sizeof(recv_buf));
    while (1) // 循环接收消息
    {
        recv_buf.mtype = 1;                                                   // 设置消息类型
        if (msg_queue_recv("msg_stm", &recv_buf, sizeof(recv_buf), 0, 0) > 0) // 接收消息
        {
            for (int i = 0; i < (*total); i++) // 遍历所有节点, 查找匹配的设备
            {
                if (key_val[i]->key == recv_buf.mkey)
                {
                    cJSON *root = cJSON_CreateObject();
                    cJSON *key = cJSON_CreateNumber(recv_buf.mkey);
                    cJSON *value = cJSON_CreateNumber(atoi(recv_buf.value));
                    cJSON_AddItemToObject(root, "key", key);
                    cJSON_AddItemToObject(root, "value", value);
                    char *out = cJSON_Print(root);
                    printf("send: %s\n", out);
                    ssize_t ret = send(ac_fd, out, sizeof(out), 0); // 发送更新后的节点数据
                    if (ret < 0)
                    {
                        perror("send error:");
                        close(ac_fd);
                        return -1;
                    }
                    free(out);
                    cJSON_Delete(root);
                }
            }
        }
        else
        {
            perror("recv error:");
            return -1;
        }
        memset(&recv_buf, 0, sizeof(recv_buf));
    }
    pthread_detach(tid);
    close(fd);
    return 0;
}